package net.butfly.bus.config.parser;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.butfly.albacore.exception.SystemException;
import net.butfly.bus.Constants;
import net.butfly.bus.config.Config;
import net.butfly.bus.config.ConfigParser;
import net.butfly.bus.config.bean.FilterBean;
import net.butfly.bus.config.bean.NodeBean;
import net.butfly.bus.filter.Filter;
import net.butfly.bus.util.XMLUtils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public abstract class XMLConfigParser extends ConfigParser {
	protected Document document;
	protected Element root;

	public XMLConfigParser(InputStream source) {
		super();
		if (null == source)
			throw new SystemException(Constants.UserError.CONFIG_ERROR, "Bus configurations invalid.");
		try {
			this.document = new SAXReader().read(source);
		} catch (DocumentException e) {
			throw new SystemException(Constants.UserError.CONFIG_ERROR, "Bus configurations invalid.", e);
		}
		this.root = this.document.getRootElement();
	}

	protected Map<String, NodeBean> parseNodes(String xpath) {
		List<Element> nodeList = this.elements(xpath);
		Map<String, NodeBean> nodesMap = new HashMap<String, NodeBean>();
		if (nodeList != null) {
			for (Element nodeEle : nodeList) {
				String nodeId = nodeEle.attributeValue("id");
				String enabled = nodeEle.attributeValue("enabled");
				if (enabled == null || enabled.trim().toUpperCase().equals("TRUE")) {
					logger.info("Node [" + nodeId + "] loading:	\n" + nodeEle.asXML());
					nodesMap.put(nodeId, this.createNodeBean(nodeId, nodeEle));
					logger.info("Node [" + nodeId + "] loaded.");
				} else {
					logger.info("Node [" + nodeId + "] disabled:	\n" + nodeEle.asXML());
				}
			}
		}
		return nodesMap;
	}

	protected abstract NodeBean createNodeBean(String nodeId, Element nodeEle);

	public void parse(Config config) {
		config.setFilterBeanList(this.parseFilters(this.elements("filter")));
	}

	public List<FilterBean> parseFilters(List<Element> filters) {
		List<FilterBean> list = new ArrayList<FilterBean>();
		for (Element filter : filters) {
			FilterBean f = parseFilter(filter);
			if (null != f)
				list.add(f);
		}
		return list;
	}

	@SuppressWarnings("unchecked")
	private FilterBean parseFilter(Element filter) {
		String title = filter.attributeValue("title");
		String attr = filter.attributeValue("enabled");
		if (null == attr || Boolean.parseBoolean(attr.toLowerCase())) {
			attr = filter.attributeValue("order");

			Map<String, String> params = new HashMap<String, String>();
			for (Element param : (List<Element>) filter.selectNodes("param"))
				params.put(param.attributeValue("name"), param.attributeValue("value"));

			Class<? extends Filter> clazz;
			try {
				clazz = (Class<? extends Filter>) Class.forName(filter.attributeValue("class"));
			} catch (Throwable e) {
				throw new SystemException(Constants.UserError.FILTER_INVOKE, "Filter类定义无效", e);
			}
			FilterBean f = new FilterBean(title, clazz, params);
			logger.info("　启用过滤器" + title);
			logAsXml(filter);
			return f;
		} else {
			logger.info("未启用过滤器" + title);
			logAsXml(filter);
			return null;
		}
	}

	protected static void logAsXml(Element element) {
		logger.debug(XMLUtils.format(element.asXML()).replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "")
				.replaceAll("\n$$", ""));
	}

	@SuppressWarnings("unchecked")
	protected List<Element> elements(String xpath) {
		return root.selectNodes(xpath);
	}
}
